package com.wzh.activity.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.wzh.activity.entity.ActivityEntity;
import com.wzh.activity.entity.GoodsEntity;
import com.wzh.activity.feign.GoodsFeign;
import com.wzh.activity.service.ActivityService;
import com.wzh.activity.vo.OrderVo;
import com.wzh.common.utils.R;
import io.lettuce.core.RedisClient;
import org.redisson.RedissonTopic;
import org.redisson.api.RLock;
import org.redisson.api.RPermitExpirableSemaphore;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wzh.common.utils.PageUtils;
import com.wzh.common.utils.Query;

import com.wzh.activity.dao.OrderInfoDao;
import com.wzh.activity.entity.OrderInfoEntity;
import com.wzh.activity.service.OrderInfoService;
import org.springframework.transaction.annotation.Transactional;


@Service("orderInfoService")
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoDao, OrderInfoEntity> implements OrderInfoService {

    @Autowired
    private GoodsFeign goodsFeign;

    @Autowired
    private OrderInfoDao orderInfoDao;

    @Autowired
    private  RedissonClient redissonClient;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        String userId = (String) params.get("userId");
        IPage<OrderInfoEntity> page = this.page(
                new Query<OrderInfoEntity>().getPage(params),
                new QueryWrapper<OrderInfoEntity>().eq("user_id",userId)
        );

        return new PageUtils(page);
    }

    @Override
    public PageUtils queryPage2(Map<String, Object> params) {
        IPage<OrderInfoEntity> page = this.page(
                new Query<OrderInfoEntity>().getPage(params),
                new QueryWrapper<OrderInfoEntity>()
        );

        return new PageUtils(page);
    }
    //原始锁业务逻辑
//    @Override
//    @Transactional
//    public R add(OrderVo orderVo){
//        String uuid = UUID.randomUUID().toString().replace("", "-");
//        try {
//            Boolean myLock2 = redisTemplate.opsForValue().setIfAbsent("myLock2", uuid, 30, TimeUnit.SECONDS);
//            if (myLock2){
//                ActivityEntity byId = (ActivityEntity) redisTemplate.boundHashOps("activity").get("item"+orderVo.getActivityId());
//                if (byId.getStockCount()>0) {
//                    //判断一个用户限购一件(解决订单超买问题)
//                    Integer count=orderInfoDao.getUserCountById(orderVo.getUserId(),orderVo.getActivityId());
//                    if (count>=1){
//                        return R.error("一个用户只能限购一次");
//                    }else {
//                        //mq异步添加订单
//                        rabbitTemplate.convertAndSend("msg",orderVo);
//                        //库存-1
//                        byId.setStockCount(byId.getStockCount()-1);
//                        redisTemplate.boundHashOps("activity").put("item"+orderVo.getActivityId(),byId);
//                        rabbitTemplate.convertAndSend("msg2",byId);
//                        return R.ok("秒杀成功");
//                    }
//                }else {
//                    return R.error("库存不足");
//                }
//            }else {
//                try {
//                    Thread.sleep(100);
//                    add(orderVo);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//            }
//        } finally {
//           // 不论结果如何，都要删除锁（避免死锁）
//                //对比删除原子性 对比是本人的锁并且删除（原子性操作避免并发请求同时执行该操作）redis+lua脚本
//                String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
//                redisTemplate.execute(new DefaultRedisScript<Long>(script,Long.class), Arrays.asList("myLock2"),uuid);
//        }
//        return R.error();
//    }

    /**
     * @Author WZH
     * @方法描述: 判断限流方法
     * @Param: OrderVo
     * @Return: Boolean
     * @Create: 2022/3/3
     */
    public Boolean getSemaphore(OrderVo orderVo){
        //查询redis有无
        Integer num = (Integer) redisTemplate.opsForValue().get(orderVo.getUserId() + "Park" + orderVo.getActivityId());
        if (num==null){
            //无就去设置
            RLock lock2 = redissonClient.getLock("myLock2");
            try {
                boolean b = lock2.tryLock();
                //再去查询判断有无
                if (b){//抢锁成功
                    //设置次数
                    redisTemplate.opsForValue().set(orderVo.getUserId() + "Park" + orderVo.getActivityId(),5,3,TimeUnit.SECONDS);
                    return true;
                }else {
                    //回旋
                    getSemaphore(orderVo);
                }
            } finally {
                //防止误删锁
                if(lock2.isLocked()){
                   if(lock2.isHeldByCurrentThread()){
                      lock2.unlock();
                   }
                }
            }
        }else {
            //有就去-1
            num=num-1;
            redisTemplate.opsForValue().set(orderVo.getUserId() + "Park" + orderVo.getActivityId(),num,3,TimeUnit.SECONDS);
            if (num<=0){
                return false;
            }else {
                return true;
            }
        }
        return false;
    }

    @Override
    @Transactional
    public R add(OrderVo orderVo) throws InterruptedException {
        Boolean b = getSemaphore(orderVo);//调用限流方法
        if (b){
            RLock lock = redissonClient.getLock("myLock");
            try {
                lock.lock();
                ActivityEntity activity = (ActivityEntity) redisTemplate.boundHashOps("activity").get("item"+orderVo.getActivityId());
             if (activity.getStockCount()>0) {//判断库存是否足够（判断库存超卖）
                 //一个用户限购一次去redis查
                 Integer count= (Integer) redisTemplate.opsForValue().get(orderVo.getUserId()+"And"+orderVo.getActivityId()+"Count");
                 if (count!=null&&count>=1){//判断判断一个用户限购一件 订单超买
                     return R.error("一个用户只能限购一次");
                 }else {
                     //库存-1
                     Integer stockCount = activity.getStockCount();
                     activity.setStockCount(activity.getStockCount() - 1);
                     redisTemplate.boundHashOps("activity").put("item" + orderVo.getActivityId(), activity);
                     ActivityEntity activity2 = (ActivityEntity) redisTemplate.boundHashOps("activity").get("item" + orderVo.getActivityId());
                     // boolean b = activityService.updateById(activity);
                     if (stockCount > activity2.getStockCount()) {//只有活动库存(解决订单超卖问题)
                         //mq异步添加订单
                         //秒杀成功立刻添加redis表示已经成功
                         redisTemplate.opsForValue().set(orderVo.getUserId() + "And" + orderVo.getActivityId() + "Count", 1, activity.getEndDate().getTime() - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
                         rabbitTemplate.convertAndSend("msg", orderVo);
                         return R.ok("秒杀成功");
                     } else {
                         return R.error("库存未减");
                     }
                 }
             }else {
                 return R.error("库存不足");
             }
            } finally {
            //if(lock.isLocked()){
            //   if(lock.isHeldByCurrentThread()){
            lock.unlock();
            //   }
            //  }
          }
        }else {
           return R.error("服务限流了");
        }
    }
    @Override
    public R updOrder(String orderNo,String orderAmount) {
        OrderInfoEntity order = baseMapper.selectOne(new QueryWrapper<OrderInfoEntity>().eq("order_no", orderNo));
        //判断金额
        if (order.getGoodsPrice().doubleValue()==Double.valueOf(orderAmount)) {
            //减商品库存
            R info = goodsFeign.info(order.getGoodsId());
            Object goodsObject = info.get("goods");
            String jsonString = JSON.toJSONString(goodsObject);
            GoodsEntity goods = JSON.parseObject(jsonString, GoodsEntity.class);
            goods.setGoodsStock(goods.getGoodsStock()-order.getGoodsCount());
            goodsFeign.update(goods);
            //修改订单状态
            order.setPayDate(new Date());
            order.setStatus(1);
            int i = baseMapper.updateById(order);
            //减用户钱
            return R.ok("支付完成");
        }
        return R.error(500,"金额有误");
    }

    @Override
    public OrderInfoEntity getByGoodsIdAndUserId(Long goodsid, String userid) {
        OrderInfoEntity orderInfoEntity = baseMapper.selectOne(new QueryWrapper<OrderInfoEntity>().eq("goods_id", goodsid).eq("user_id", userid));
        return orderInfoEntity;
    }


}